// Copyright 2009 sbva project
//
// This file is part of sbva,
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.googlecode.sbva;

import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.util.MessageResources;
import org.apache.struts.validator.Resources;

/**
 * Utility class for adapting a JSR-303 Bean validation adaptor with a Struts 1
 * form validation.  This allows jsp-303 Bean Validation to be used in place of
 * org.apache.struts.validator.ValidatorPlugIn.
 * <p>
 * This can be used in an ActionForm subclass like this:
 * <blockquote><pre>
 * 
 * public class UserForm extends ActionForm {
 *   private static StrutsBeanValidationAdapter beanValidationToStrutsConverter
 *     = new DefaultStrutsBeanValidationAdapter();
 *   .
 *   .
 *   .
 *   &#064;Override
 *   public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
 *     return beanValidationToStrutsConverter.beanValidationErrorsToActionErrors(this, request);
 *   }
 *   .
 *   .
 *   .
 * }
 * </pre></blockquote>
 *
 * In your business object you can specify validation constraints
 * as defined in JSR-303 bean validation like this:
 *
 * <blockquote><pre>
 * public class Address implements Serializable {
 *
 *  &#064;NotNull
 *  &#064;Size(min=1, message="struts://input.required/?0=create.user.address.address")
 *  private String address0;
 *
 * </pre></blockquote>
 *
 *
 */
public class DefaultStrutsBeanValidationAdapter<T> extends StrutsBeanValidationAdapter<T> {

   private static Log log = LogFactory.getLog(DefaultStrutsBeanValidationAdapter.class);

   private boolean returnNull = false;

   /**
    * Creates an empty ActionErrors and delegates to {@link #beanValidationErrorsToActionErrors(java.lang.Object, javax.servlet.http.HttpServletRequest, org.apache.struts.action.ActionErrors, java.lang.Class<T>[]) }
    *
    * @see #beanValidationErrorsToActionErrors(java.lang.Object, javax.servlet.http.HttpServletRequest, org.apache.struts.action.ActionErrors, java.lang.Class<T>[])
    *
    * @param model
    * @param lookup
    * @param groups
    * @return
    */
   public ActionErrors beanValidationErrorsToActionErrors(T model, HttpServletRequest request, Class<T>... groups) {
      ActionErrors errors = new ActionErrors();

      return beanValidationErrorsToActionErrors(model, request, errors, groups);
   }

   /**
    * This method performs the adapting between jsr-303 bean validation and
    * Struts 1 validation.  It shold be invoked in the ActionForm validate
    * method like thid.
    *
    * <code>
    * public class UserForm extends ActionForm {
    *   private static StrutsBeanValidationAdapter beanValidationToStrutsConverter =
    *     new DefaultStrutsBeanValidationAdapter();
    * .
    * .
    * .
    *   @Override
    *   public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
    *     return beanValidationToStrutsConverter.beanValidationErrorsToActionErrors(this, request);
    *   }
    * .
    * .
    * .
    * }
    * </code>
    *
    * This will invoke {@link #mapPropertyToFormInput(java.lang.String)  } for each error encounterd.
    *
    * @param model - the object containg the JSR-303 bean validations to be validated.  This is usually an ActionForm.
    * @param lookup - the current HttpServletRequest parameters
    * @param errors - the ActionErrors to add the JSR-303 BeanValidation errors to for display using <code>&gt;html:errors key="..."/&lt;
    * @param groups - the groups that define what validations should occur.
    * @return all ActionErrors to display to the user.
    *
    */
   public ActionErrors beanValidationErrorsToActionErrors(T model, HttpServletRequest request, ActionErrors errors, Class<T>... groups) {

      final MessageResources currentResource = Resources.getMessageResources(request);

      currentResource.setReturnNull(isReturnNull());

      LookupProperty lookup = new LookupProperty() {

         public String lookup(String value) {

            String tmpValue = currentResource.getMessage(value);

            return tmpValue;
         }
      };

      PropertyAndErrorMessages genericErrors = new PropertyAndErrorMessages();

      beanValidationErrorsToActionErrors(model, lookup, genericErrors, groups);

      return map2ActionErrors(errors, genericErrors);
   }

   /**
    *
    * Perform no mapping and just pass throguth the propeerty name.
    *
    * @param propertyName
    * @return propertyName
    */
   public String mapPropertyToFormInput(String propertyName) {
      if (log.isDebugEnabled()) {
         log.debug("property=" + propertyName);
      }
      return propertyName;
   }

   /**
    *
    * {@link  http://struts.apache.org/1.x/apidocs/org/apache/struts/util/MessageResources.html MessageResources.getReturnNull}
    *
    * @return
    */
   public boolean isReturnNull() {
      return returnNull;
   }

   /**
    *
    * {@link  http://struts.apache.org/1.x/apidocs/org/apache/struts/util/MessageResources.html MessageResources.setReturnNull}
    *
    * @param returnNull
    */
   public void setReturnNull(boolean returnNull) {
      this.returnNull = returnNull;
   }


}
